package coreCache

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/goccy/go-json"

	"gitee.com/xgh2012/api-core/coreError"
	"github.com/redis/go-redis/v9"
)

// Cache 缓存接口
type Cache interface {
	Get(ctx context.Context, key string) (string, error)
	Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error
	Del(ctx context.Context, keys ...string) error
	Exists(ctx context.Context, key string) (bool, error)
	Expire(ctx context.Context, key string, expiration time.Duration) error
	TTL(ctx context.Context, key string) (time.Duration, error)
}

// RedisCache Redis缓存实现
type RedisCache struct {
	client *redis.Client
	prefix string
}

// NewRedisCache 创建Redis缓存实例
func NewRedisCache(client *redis.Client, prefix string) *RedisCache {
	return &RedisCache{
		client: client,
		prefix: prefix,
	}
}

// buildKey 构建带前缀的key
func (r *RedisCache) buildKey(key string) string {
	if r.prefix == "" {
		return key
	}
	return fmt.Sprintf("%s:%s", r.prefix, key)
}

// Get 获取缓存值
func (r *RedisCache) Get(ctx context.Context, key string) (string, error) {
	result, err := r.client.Get(ctx, r.buildKey(key)).Result()
	if err != nil {
		if errors.Is(err, redis.Nil) {
			return "", coreError.ErrNotFound
		}
		return "", coreError.WrapError(err, "redis get failed")
	}
	return result, nil
}

// Set 设置缓存值
func (r *RedisCache) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
	var val string
	switch v := value.(type) {
	case string:
		val = v
	case []byte:
		val = string(v)
	default:
		// 对于其他类型，使用JSON序列化
		data, err := json.Marshal(value)
		if err != nil {
			return coreError.WrapError(err, "json marshal failed")
		}
		val = string(data)
	}

	err := r.client.Set(ctx, r.buildKey(key), val, expiration).Err()
	if err != nil {
		return coreError.WrapError(err, "redis set failed")
	}
	return nil
}

// Del 删除缓存
func (r *RedisCache) Del(ctx context.Context, keys ...string) error {
	if len(keys) == 0 {
		return nil
	}

	buildKeys := make([]string, len(keys))
	for i, key := range keys {
		buildKeys[i] = r.buildKey(key)
	}

	err := r.client.Del(ctx, buildKeys...).Err()
	if err != nil {
		return coreError.WrapError(err, "redis del failed")
	}
	return nil
}

// Exists 检查key是否存在
func (r *RedisCache) Exists(ctx context.Context, key string) (bool, error) {
	result, err := r.client.Exists(ctx, r.buildKey(key)).Result()
	if err != nil {
		return false, coreError.WrapError(err, "redis exists failed")
	}
	return result > 0, nil
}

// Expire 设置过期时间
func (r *RedisCache) Expire(ctx context.Context, key string, expiration time.Duration) error {
	err := r.client.Expire(ctx, r.buildKey(key), expiration).Err()
	if err != nil {
		return coreError.WrapError(err, "redis expire failed")
	}
	return nil
}

// TTL 获取剩余过期时间
func (r *RedisCache) TTL(ctx context.Context, key string) (time.Duration, error) {
	result, err := r.client.TTL(ctx, r.buildKey(key)).Result()
	if err != nil {
		return 0, coreError.WrapError(err, "redis ttl failed")
	}
	return result, nil
}

// GetJSON 获取JSON格式的缓存值并反序列化
func (r *RedisCache) GetJSON(ctx context.Context, key string, dest interface{}) error {
	val, err := r.Get(ctx, key)
	if err != nil {
		return err
	}

	err = json.Unmarshal([]byte(val), dest)
	if err != nil {
		return coreError.WrapError(err, "json unmarshal failed")
	}
	return nil
}

// SetJSON 设置JSON格式的缓存值
func (r *RedisCache) SetJSON(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
	return r.Set(ctx, key, value, expiration)
}

// MemoryCache 内存缓存实现（简单实现，适用于单机场景）
type MemoryCache struct {
	data map[string]*cacheItem
}

type cacheItem struct {
	value      string
	expiration time.Time
}

// NewMemoryCache 创建内存缓存实例
func NewMemoryCache() *MemoryCache {
	return &MemoryCache{
		data: make(map[string]*cacheItem),
	}
}

// Get 获取缓存值
func (m *MemoryCache) Get(ctx context.Context, key string) (string, error) {
	item, exists := m.data[key]
	if !exists {
		return "", coreError.ErrNotFound
	}

	if !item.expiration.IsZero() && time.Now().After(item.expiration) {
		delete(m.data, key)
		return "", coreError.ErrNotFound
	}

	return item.value, nil
}

// Set 设置缓存值
func (m *MemoryCache) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
	var val string
	switch v := value.(type) {
	case string:
		val = v
	case []byte:
		val = string(v)
	default:
		data, err := json.Marshal(value)
		if err != nil {
			return coreError.WrapError(err, "json marshal failed")
		}
		val = string(data)
	}

	item := &cacheItem{
		value: val,
	}

	if expiration > 0 {
		item.expiration = time.Now().Add(expiration)
	}

	m.data[key] = item
	return nil
}

// Del 删除缓存
func (m *MemoryCache) Del(ctx context.Context, keys ...string) error {
	for _, key := range keys {
		delete(m.data, key)
	}
	return nil
}

// Exists 检查key是否存在
func (m *MemoryCache) Exists(ctx context.Context, key string) (bool, error) {
	_, err := m.Get(ctx, key)
	return err == nil, nil
}

// Expire 设置过期时间
func (m *MemoryCache) Expire(ctx context.Context, key string, expiration time.Duration) error {
	item, exists := m.data[key]
	if !exists {
		return coreError.ErrNotFound
	}

	if expiration > 0 {
		item.expiration = time.Now().Add(expiration)
	} else {
		item.expiration = time.Time{}
	}

	return nil
}

// TTL 获取剩余过期时间
func (m *MemoryCache) TTL(ctx context.Context, key string) (time.Duration, error) {
	item, exists := m.data[key]
	if !exists {
		return 0, coreError.ErrNotFound
	}

	if item.expiration.IsZero() {
		return -1, nil // 永不过期
	}

	ttl := time.Until(item.expiration)
	if ttl <= 0 {
		delete(m.data, key)
		return 0, coreError.ErrNotFound
	}

	return ttl, nil
}
